//----------------------------------------------------------------------------
//
// (C) Copyrights MARIN/MSCN  2004 
//
//----------------------------------------------------------------------------
//
// $Source: $
//
// $Author: A. Abbing $
//
// $Description: $
//
// $End: $
//
//----------------------------------------------------------------------------

#ifndef __mst_Vector2_h__
#define __mst_Vector2_h__

#include "Math.h"
#include "string.h"
#include "Matrix4.h"
#include "Stream.h"
#include <iostream>

#if defined(min) && !defined(mst_min)
#define mst_min min
#undef min
#endif

#if defined(max) && !defined(mst_max)
#define mst_max max
#undef max
#endif

namespace mst {

/*! 
  \class Vector2 mst/Vector2.h
  \brief 2D vector template class
  \ingroup math
*/

  template<class Type> class Vector2 {
      Type m_v[2];

    public:
      /** return the size of the vector */
      virtual unsigned int size() const { return 2; }

      /** Get vector internal data. */
      Type const* getData() const {
        return m_v;
      }

      /*!
	\fn Vector2()
	\brief Construct a 2D vector with initial values (0.0, 0.0)
      */
      Vector2() { memset((void*) m_v, 0, 2*sizeof(Type)); }
      /*!
	\fn Vector2(Type x, Type y)
	\brief Construct a 2D vector
	\param x the x initialisation value
	\param y the x initialisation value
      */
      Vector2(Type x, Type y) { set(x, y); }

      /*!
	\fn Vector2(Type v)
	\brief Construct a 2D vector
	\param v the x,y initialisation value
      */
      Vector2(Type v) { set(v, v); }

      /*!
	\fn virtual ~Vector2()
	\brief destructor
      */
      virtual ~Vector2() {}

      /*!
	\fn void set(const Vector2<Type> &v)
	\param v the initialisation vector
	\brief Set the value of the vector
      */
      void set(const Vector2<Type> &v) { m_v[0] = v[0]; m_v[1] = v[1]; }
      /*!
	\fn void get(Type &x, Type &y) const
	\brief Get the values of the vector
	\param x the x value
	\param y the y value
      */
      void get(Type &x, Type &y) const { x= m_v[0]; y = m_v[1]; }
      /*!
	\fn void set(Type x, Type y)
	\brief Set the value of the vector
	\param x the x initialisation value
	\param y the y initialisation value
      */
      void set(Type x, Type y) { m_v[0] = x; m_v[1] = y; }

      /*!
	\fn Type angle() const
	\brief return the angle of the vector
      */
      Type angle() const { return mst::atan2(m_v[1], m_v[0]); }
      /*!
	\fn Type angle(const Vector2<Type> &a) const
	\brief return the length between two vectors
	\param a the second vector
      */
      Type angle(const Vector2<Type> &a) const {
        return mst::atan2(m_v[1]-a[1], m_v[0]-a[0]);
      }

      /*!
	\fn Type sqrLength() const
	\brief return the squared length of the vector
      */
      Type sqrLength() const { 
        return m_v[0]*m_v[0] + m_v[1]*m_v[1]; 
      }

      /*!
	\fn Type length() const
	\brief return the length of the vector
      */
      Type length() const { 
        return mst::sqrt(sqrLength());
      }

      /*!
	\fn Type sqrDistance(const Vector2<Type> &v) const
	\param v the second vector
	\brief return the square distance between two vectors
      */
      Type sqrDistance(const Vector2<Type> &v) const {
        Type x = v[0] - m_v[0];
        Type y = v[1] - m_v[1];
        return x*x + y*y;
      }
      /*!
	\fn void clip(const Vector2<Type> &minv, const Vector2<Type> &maxv)
	\brief clip the vector against the minimum and maximum vector values
	\param minv the minimum clip value
	\param maxv the maximum clip value
      */
      void clip(const Vector2<Type> &minv, const Vector2<Type> &maxv) {
        m_v[0] = mst::clamp(m_v[0], minv[0], maxv[0]);
        m_v[1] = mst::clamp(m_v[1], minv[1], maxv[1]);
      }
      /*!
	\fn Type distance(const Vector2<Type> &v) const
	\param v the second vector
	\brief return the distance between two vectors
      */
      Type distance(const Vector2<Type> &v) const 
      { return mst::sqrt(sqrDistance(v)); }

      /*!
	\fn Type &operator[](int i)
	\param i index
	\brief Accesses indexed component of vector
      */
      Type &operator[](int i) { return m_v[i]; }
	
      /*!
	\fn const Type &operator[](int i) const
	\param i index
	\brief Accesses indexed component of vector
      */
      const Type &operator[](int i) const { return m_v[i]; }

      /*! \fn void max(const Vector2<Type> &m)
        \brief Maximize the this vector
        \param m The maximum value
      */
      void max(const Vector2<Type> &m)
      {
        m_v[0] = mst::max(m_v[0], m[0]);
        m_v[1] = mst::max(m_v[1], m[1]);
      }

      /*! \fn void max(const Vector2<Type> &v, const Vector2<Type> &m)
        \brief Maximize the this vector 
        \param v The value vector
        \param m The maximum value
      */
      void max(const Vector2<Type> &v, const Vector2<Type> &m)
      {
        m_v[0] = mst::max(v[0], m[0]);
        m_v[1] = mst::max(v[1], m[1]);
      }

      /*! \fn void min(const Vector2<Type> &m)
        \brief Minimize the this vector
        \param m The minimum value
      */
      void min(const Vector2<Type> &m)
      {
        m_v[0] = mst::min(m_v[0], m[0]);
        m_v[1] = mst::min(m_v[1], m[1]);
      }

      /*! \fn void min(const Vector2<Type> &v, const Vector2<Type> &m)
        \brief Minimize the this vector 
        \param v The value vector
        \param m The minimum value
      */
      void min(const Vector2<Type> &v, const Vector2<Type> &m)
      {
        m_v[0] = mst::min(v[0], m[0]);
        m_v[1] = mst::min(v[1], m[1]);
      }

      /*!
	\fn void copy(const Vector2<Type> &v)
	\param v Vector to copy
	\brief Copy vector
      */
      void copy(const Vector2<Type> &v) { set(v[0], v[1]); }
      /*!
	\fn void negate(const Vector2<Type> &v)
	\brief Negate the current vector
      */
      void negate(const Vector2<Type> &v) { set(-v[0], -v[1]); }
      /*!
	\fn Type normalize()
	\brief Normalise the current vector
      */
      Type normalize() {
        Type l = length();
        *this *= (l < mst::eta(l)) ? mst::huge(l) : ((Type) 1) / l;
        return l;
      }
      /*!
	\fn void scale(Type s, const Vector2<Type> &v)
	\param s The fraction of the vector
	\param v The vector
	\brief Set a scaled vector
      */
      void scale(Type s, const Vector2<Type> &v) { set(s*v[0], s*v[1]); }
      /*!
	\fn void addScaled(const Vector2<Type>& a, Type s, const Vector2<Type>& b)
	\param a The first vector
	\param s The fraction of vector b
	\param b The second vector
	\brief Add a scaled vector
      */
      void addScaled(const Vector2<Type>& a, Type s, const Vector2<Type>& b) {
        m_v[0] = a[0] + s * b[0];
        m_v[1] = a[1] + s * b[1];
      }
      /*!
	\fn void combine(Type sa, const Vector2<Type>& a, Type sb, const Vector2<Type>& b)
	\param sa The fraction of vector a
	\param a The first vector
	\param sb The fraction of vector b
	\param b The second vector
	\brief Combine two vectors
      */
      void combine(Type sa, const Vector2<Type>& a, Type sb, const Vector2<Type>& b) {
        m_v[0] = sa * a[0] + sb * b[0];
        m_v[1] = sa * a[1] + sb * b[1];
      }
      /*!
	\fn bool equal(const Vector2<Type> &v) const
	\param v The vector
	\brief Test for component-wise equality
      */
      bool equal(const Vector2<Type> &v) const {
        return m_v[0] == v[0] && m_v[1] == v[1];
      }
      /*!
	\fn bool almostEqual(const Vector2<Type>& v, Type tol) const
	\param v the second vector
	\param tol the tolerance value
	\brief Tests for approximate component-wise equality
	\sa equal

	Tests for approximate component-wise equality of
	two vectors. It returns false or true depending on whether
	the absolute value of the difference between each pair of components is
	less than the tolerance. 
      */
      bool almostEqual(const Vector2<Type>& v, Type tol) const {
        return mst::equal(m_v[0],v[0],tol) && 
          mst::equal(m_v[1], v[1], tol);
      }

      /*!
	\fn bool equal(const Vector2<Type>& v, Type tol) const
	\param v the second vector
	\param tol the tolerance value
	\brief Tests for approximate component-wise equality
	\sa almostEqual

	Tests for approximate component-wise equality of
	two vectors. It returns false or true depending on whether
	the absolute value of the difference between each pair of components is
	less than the tolerance. 
      */
      bool equal(const Vector2<Type>& v, Type tol) const
      { return almostEqual(v, tol); }

      /*!
	\fn bool almostEqual(const Vector2<Type>& v, const Vector2<Type>& tol) const
	\param v the second vector
	\param tol the tolerance value
	\brief Tests for approximate component-wise equality
	\sa equal

	Tests for approximate component-wise equality of
	two vectors. It returns false or true depending on whether
	the absolute value of the difference between each pair of components is
	less than the tolerance. 
      */
      bool almostEqual(const Vector2<Type>& v, const Vector2<Type>& tol) const {
        return mst::equal(m_v[0],v[0],tol[0]) && 
          mst::equal(m_v[1], v[1], tol[1]);
      }

      /*!
	\fn bool equal(const Vector2<Type>& v, const Vector2<Type>& tol) const
	\param v the second vector
	\param tol the tolerance value
	\brief Tests for approximate component-wise equality
	\sa almostEqual

	Tests for approximate component-wise equality of
	two vectors. It returns false or true depending on whether
	the absolute value of the difference between each pair of components is
	less than the tolerance. 
      */
      bool equal(const Vector2<Type>& v, const Vector2<Type>& tol) const 
      { return almostEqual(v, tol); }

      /*!
	\fn Type dot(const Vector2<Type>& v) const
	\param v the second vector
	\brief Calculate the dot product of two vectors
      */
      Type dot(const Vector2<Type>& v) const {
        return m_v[0]*v[0] + m_v[1]*v[1];
      }
      /*!
	\fn void add(const Vector2<Type> &a, const Vector2<Type> &b)
	\param a The first vector
	\param b The second vector
	\brief Add two vectors
      */
      void add(const Vector2<Type> &a, const Vector2<Type> &b) {
        m_v[0] = a[0] + b[0];
        m_v[1] = a[1] + b[1];
      }
      /*!
	\fn void sub(const Vector2<Type> &a, const Vector2<Type> &b)
	\param a The first vector
	\param b The second vector
	\brief Subtract two vectors
      */
      void sub(const Vector2<Type> &a, const Vector2<Type> &b) {
        m_v[0] = a[0] - b[0];
        m_v[1] = a[1] - b[1];
      }
      /*!
	\fn void xformPt(const Vector2<Type>& v, const mst::Matrix4<Type>& m)
	\param v The vector
	\param m The matrix
	\brief Transform of a point
      */
      void xformPt(const Vector2<Type>& v, const mst::Matrix4<Type>& m) {
        Type t0, t1, w;
        t0 = v[0];
        t1 = v[1];
        m_v[0] = t0 * m[0][0] + t1 * m[1][0] + m[3][0];
        m_v[1] = t0 * m[0][1] + t1 * m[1][1] + m[3][1];
        w = (t0*m[0][3] + t1*m[1][3] + m[3][3]);
        if (w != ((Type) 1)) {
          if (mst::abslt(w, mst::eta(w))) w = mst::eta(w);
          *this /= w;
        }
      }
      /*!
	\fn void xformVec(const Vector2<Type>& v, const mst::Matrix4<Type>& m)
	\param v The vector
	\param m The matrix
	\brief Transform of a vector
      */
      void xformVec(const Vector2<Type>& v, const mst::Matrix4<Type>& m) {
        Type  t0, t1;
        t0 = v[0]; t1 = v[1];
        m_v[0] = t0 * m[0][0] + t1 * m[1][0];
        m_v[1] = t0 * m[0][1] + t1 * m[1][1];
      }
      /*!
	\fn void fullXformPt(const Vector2<Type>& v, const mst::Matrix4<Type>& m)
	\param v The vector
	\param m The matrix
	\brief Full transform of a vector
      */
      void fullXformPt(const Vector2<Type>& v, const mst::Matrix4<Type>& m) {
        Type t0, t1, w;
        t0 = v[0];
        t1 = v[1];
        m_v[0] = t0 * m[0][0] + t1 * m[1][0] + m[3][0];
        m_v[1] = t0 * m[0][1] + t1 * m[1][1] + m[3][1];
        w = t0*m[0][3] + t1*m[1][3] + m[3][3];
        if (w != (Type) 1) {
          if (mst::abslt(w, mst::eta(w))) w = mst::eta(w);
          *this /= w;
        }
      }

      /*!
	\fn bool operator==(const Vector2<Type> &v)
	\param v The vector
	\brief Test for equality of a vector with the current vector
      */
      bool operator==(const Vector2<Type> &v) { return equal(v); }
      /*!
	\fn bool operator!=(const Vector2<Type> &v)
	\param v The vector
	\brief Test for inequality of a vector with the current vector
      */
      bool operator!=(const Vector2<Type> &v) { return !equal(v); }
      /*!
	\fn void operator-=(const Vector2<Type> &v)
	\param v The vector
	\brief Subtract a vector of the current vector
      */
      void operator-=(const Vector2<Type> &v) {
        m_v[0] -= v[0];
        m_v[1] -= v[1];
      }
      /*!
	\fn void operator+=(const Vector2<Type> &v)
	\param v The vector
	\brief Add a vector to the current vector
      */
      void operator+=(const Vector2<Type> &v) {
        m_v[0] += v[0];
        m_v[1] += v[1];
      }
      /*!
	\fn void operator/=(Type s)
	\param s The scalar
	\brief Devide the current vector by a scalar
      */
      void operator/=(Type s) {
        m_v[0] /= s;
        m_v[1] /= s;
      }
      /*!
	\fn void operator*=(Type s)
	\param s The scalar
	\brief Multiply the current vector by a scalar
      */
      void operator*=(Type s) {
        m_v[0] *= s;
        m_v[1] *= s;
      }

      /*! \fn bool operator<(const Vector2<Type> &v)
	\brief Componentwise smaller than check
      */
      bool operator<(const Vector2<Type> &v)
      {
        return (m_v[0] < v[0]) || (m_v[1] < v[1]);
      }

      /*! \fn bool operator>(const Vector2<Type> &v)
	\brief Componentwise larger than check
      */
      bool operator>(const Vector2<Type> &v)
      {
        return (m_v[0] > v[0]) || (m_v[1] > v[1]);
      }

    public:	// Warning: return by value can be slow
      /*!
	\fn Vector2<Type> operator-() const
	\brief Return the result of a unary vector negation
      */
      Vector2<Type> operator-() const { return Vector2<Type>(-m_v[0], -m_v[1]); }
      /*!
	\fn Vector2<Type> operator+(const Vector2<Type>& v) const
	\param v The 2D vector
	\brief Return the result of  a vector addition
      */
      Vector2<Type> operator+(const Vector2<Type>& v) const {
        return Vector2<Type>(m_v[0]+v[0], m_v[1]+v[1]);
      }
      /*!
	\fn Vector2<Type> operator-(const Vector2<Type>& v) const
	\param v The 2D vector
	\brief Return the result of a vector subtraction
      */
      Vector2<Type> operator-(const Vector2<Type>& v) const {
        return Vector2<Type>(m_v[0]-v[0], m_v[1]-v[1]);
      }
      /*!
	\fn Vector2<Type>& operator=(const Vector2<Type>& v) 
	\param v The 2D vector
	\brief Assign a vector 
      */
      Vector2<Type>& operator=(const Vector2<Type>& v) {
        set(v[0], v[1]);
        return *this;
      }
      /*!
	\fn friend Vector2<Type> operator*(Type s, const Vector2<Type>& v)
	\param s The scalar
	\param v The 2D vector
	\brief Multiply a vector by a scalar
      */
      friend Vector2<Type> operator*(Type s, const Vector2<Type>& v)
      { return Vector2<Type>(v[0]*s, v[1]*s); }
		
      /*!
	\fn friend Vector2<Type> operator*(const Vector2<Type>& v, Type s)
	\param v The 2D vector
	\param s The scalar
	\brief Multiply a vector by a scalar
      */
      friend Vector2<Type> operator*(const Vector2<Type>& v, Type s)
      { return Vector2<Type>(v[0]*s, v[1]*s); }
      /*!
	\fn friend Vector2<Type> operator/(const Vector2<Type>& v, Type s)
	\param v The 2D vector
	\param s The scalar
	\brief Devide a vector by a scalar
      */
      friend Vector2<Type> operator/(const Vector2<Type>& v, Type s)
      { s = ((Type) 1)/s; return Vector2<Type>(v[0]*s, v[1]*s); }
		
      /*!
	\fn friend Vector2<Type> operator*(const Vector2<Type>& v, const mst::Matrix4<Type>& m)
	\param v The 2D vector
	\param m The 4x4 homogeneous matrix
	\brief multiply a vector by a matrix
      */
      friend Vector2<Type> operator*(const Vector2<Type>& v, const mst::Matrix4<Type>& m)
      {
        // transform as point (w=1), assuming affine transformation
        // i.e. does not use slower dst.xformFullPt().
        Vector2<Type> dst; dst.xformPt(v, m); return dst;
      }

      /*!
	\fn friend Vector2<Type> operator*(const Vector2<Type>& a, const Vector2<Type>& b)
	\param a The 2D vector
	\param b The 2D vector
	\brief multiply 2 2D vectors
      */
      friend Vector2<Type> operator*(const Vector2<Type>& a, const Vector2<Type>& b)
      {	Vector2<Type> r(a[0]*b[0], a[1]*b[1]);
      return r;
      }
  };

/*! 
  \typedef Vector2f
  \brief float specialisation of a 2D vector
  \ingroup math
*/
  typedef Vector2<float> Vector2f;

/*! 
  \typedef Vector2d
  \brief double specialisation of a 2D vector
  \ingroup math
*/
  typedef Vector2<double> Vector2d;

/*! 
  \fn template<class Type> std::ostream& operator<<(std::ostream &s, const mst::Vector2<Type> &v)
  \brief stream output operator of a 2D vector
  \ingroup io
*/
  template<class Type> std::ostream& operator<<(std::ostream &s, const mst::Vector2<Type> &v)
  { s << v[0] << " " << v[1]; return s; }

/*! 
  \fn template<class Type> std::istream& operator>>(std::istream &s, const mst::Vector2<Type> &v)
  \brief stream input operator of a 2D vector
  \ingroup io
*/
  template<class Type> std::istream& operator>>(std::istream &s, const mst::Vector2<Type> &v)
  { char c; s >> v[0] >> c >> v[1]; return s; }

/*! 
  \fn template<class T> mst::Vector2<T> abs(const mst::Vector2<T> &v)
  \brief return absolute value vector
  \ingroup math
*/
  template<class T> mst::Vector2<T> abs(const mst::Vector2<T> &v)
  {	mst::Vector2<T> res(mst::abs(v[0]), mst::abs(v[1]));
  return res;
  }

/*! 
  \fn template<class Type> mst::ostream& operator<<(mst::ostream &s, const mst::Vector2<Type> &v)
  \brief mst::ostream output operator
  \ingroup io
*/
  template<class Type> mst::ostream& operator<<(mst::ostream &s, const mst::Vector2<Type> &v)
  {
    s << v[0] << v[1];
    return s;
  }

/*! 
  \fn template<class Type> mst::istream& operator>>(mst::istream &s, mst::Vector2<Type> &v)
  \brief mst::istream input operator
  \ingroup io
*/
  template<class Type> mst::istream& operator>>(mst::istream &s, mst::Vector2<Type> &v)
  {
    s >> v[0] >> v[1];
    return s;
  }

}

#endif
